package com.icekrvams.air

import android.util.Base64
import android.view.MotionEvent
import android.view.View
import android.widget.Toast
import kotlinx.coroutines.*
import kotlin.math.abs

/**
 * 给 View 添加“彩蛋”或者长按回调事件。
 * encode:String(Base64.encode("".toByteArray(), Base64.DEFAULT))
 * @param timeInMillis 长按指定时长（单位毫秒）。
 * @param base64Str 经过 base64 编码的字符串，若不为空，则会在满足条件后弹出 Toast，内容为对传入字符的 Base64 解码结果。
 * @param longPressConditionsMetListener 若不为空，则会在满足条件后，进行回调。
 */
@JvmOverloads
fun View.setLongPressEventListener(
    timeInMillis: Long,
    base64Str: String? = null,
    longPressConditionsMetListener: LongPressConditionsMetListener? = null
) {
    val moveRadius = 50.0f// 触摸半径，移动超出该半径，则视为无效。
    var downX = 0.0f
    var downY = 0.0f
    var conditionsMet = false
    var delayJob: Job? = null

    /**
     * 重置或首次启动 Job,计时指定时间。
     */
    fun resetJob() {
        delayJob = CoroutineScope(Dispatchers.IO).launch {
            delay(timeInMillis)
            if (!isActive) return@launch
            withContext(Dispatchers.Main) {
                conditionsMet = true
                base64Str?.let {
                    val decodedStr =
                        String(Base64.decode(it.toByteArray(), Base64.DEFAULT))
                    Toast.makeText(context, decodedStr, Toast.LENGTH_LONG).show()
                }
                longPressConditionsMetListener?.onConditionsMet()
            }
        }
    }

    setOnTouchListener { _, event ->

        /**
         * 取消任务。
         * @return 取消时，是否已经达到条件。
         */
        fun cancelJob(): Boolean {
            // 抬起时，取消计时。
            if (delayJob?.isActive == true) {
                delayJob?.cancel()
            }
            val isConditionsMet = conditionsMet
            // 状态回滚。
            conditionsMet = false
            return isConditionsMet
        }

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                downX = event.x
                downY = event.y
                // 按下时，重新计时。
                resetJob()
            }
            MotionEvent.ACTION_UP -> {
                // 未达到条件，继续响应点击事件。
                if (!cancelJob()) {
                    performClick()
                }
            }
            MotionEvent.ACTION_CANCEL -> {
                cancelJob()
            }
            MotionEvent.ACTION_MOVE -> {
                // 触摸超出指定区域，视为长按无效。
                if (delayJob?.isActive == true
                    && abs(event.x - downX) > moveRadius || abs(event.y - downY) > moveRadius
                ) {
                    cancelJob()
                }
            }
        }
        true
    }
}

fun interface LongPressConditionsMetListener {
    fun onConditionsMet()
}
